﻿using System.Collections;
using System.Collections.Generic;
#if !UNITY_WEBPLAYER
using System.IO;
#endif
using UnityEngine;
using UnityEngine.UI;
using System;

public class UIGameLoading : MonoBehaviour
{
    string luaABname = "lua";
    public Text txtVersion;
    public Text txtRes;
    public Text txtSize;
    public Text txtSize2;
    public Text txtSpeed;
    public Slider progressBar;

    List<AssetBundleInfo> listDown;

    Dictionary<string, AssetBundleInfo> dicServer;
    Dictionary<string, AssetBundleInfo> dicLocal;

    string timeServerString;
    string timeLocalString;

    uint timeServer { get { return uint.Parse(timeServerString); } }
    uint timeLocal { get { return uint.Parse(timeLocalString); } }

    float allSize;
    float downSize;

    public void Start()
    {
        if (GameConfig.useAssetBundle == false)
        {
            string[] arr = File.ReadAllText(GameConfig.assetBundlePath + "/assetslist.txt").Split('\n');
            dicLocal = CreateAssetDictionary(arr);
            StartCoroutine("InitGame");
            return;
        }

        if (Directory.Exists(GameConfig.assetBundlePath) == false)
            Directory.CreateDirectory(GameConfig.assetBundlePath);

        CopyDataFromStreaming();
    }

    /// <summary>
    /// 检测是否需要从本地导入初始包
    /// </summary>
    private void CopyDataFromStreaming()
    {
        if (File.Exists(Path.Combine(GameConfig.assetBundlePath, "assetslist.txt")) == false) //无初始资源，从本地StreamingAssets目录导入
        {
            Debug.Log("CopyDataFromStreaming GameConfig.assetBundlePath  " + GameConfig.assetBundlePath);
            StartCoroutine(CopyStreaming());
        }
        else StartLoad(); //有初始资源，与服务器版本开始比对
    }

    /// <summary>
    /// 从本地导入初始资源包
    /// </summary>
    /// <returns></returns>
    private IEnumerator CopyStreaming()
    {
        progressBar.gameObject.SetActive(true);
        progressBar.value = 0;
        txtRes.text = "首次进入游戏初始化资源";
        yield return new WaitForEndOfFrame();
        string wwwStreamingAssetBundlePath = Path.Combine(GameConfig.wwwStreamingAssetsPath, "AssetBundle");

        //Debug.Log("CopyStreaming wwwStreamingAssetBundlePath  " + wwwStreamingAssetBundlePath);
        WWW www = new WWW(Path.Combine(Path.Combine(GameConfig.wwwStreamingAssetsPath, "AssetBundle"), "assetslist.txt"));

        while (www.isDone == false)
        {
            yield return new WaitForEndOfFrame();
        }

        if (string.IsNullOrEmpty(www.error) == false)
        {
            StartCoroutine(CopyStreaming());
            yield break;
        }

        string txtAssetslist = www.text;
        string[] arrAssetslist = www.text.Split('\n');

        for (int i = 1; i < arrAssetslist.Length; i++)
        {
            string[] arrData = arrAssetslist[i].Split(',');

            progressBar.value = (i + 1f) / arrAssetslist.Length;

            string fileName = arrData[1] + "_" + arrData[2];
            string abname = arrData[1];
            www = new WWW(Path.Combine(wwwStreamingAssetBundlePath, fileName));

            while (www.isDone == false)
            {
                yield return new WaitForEndOfFrame();
            }
            if (string.IsNullOrEmpty(www.error) == false)
            {
                i--;
                continue;
            }
            File.WriteAllBytes(Path.Combine(GameConfig.assetBundlePath, abname), www.bytes);

            yield return new WaitForFixedUpdate();
        }

        File.WriteAllText(Path.Combine(GameConfig.assetBundlePath, "assetslist.txt"), txtAssetslist);

        StartLoad();
    }

    /// <summary>
    /// 获取并校对服务器与本地清单资源包列表，将需下载资源包加入下载队列，一致则开始加载资源
    /// </summary>
    private void StartLoad()
    {
        listDown = new List<AssetBundleInfo>();

        if (string.IsNullOrEmpty(GameConfig.AssetIP) == false)
        {
            StartCoroutine(CheckResources());
        }
        else
        {
            Debug.Log("bb");
            string[] arr = File.ReadAllText(GameConfig.assetBundlePath + "/assetslist.txt").Split('\n');
            timeLocalString = arr[0];
            dicLocal = CreateAssetDictionary(arr);
            txtVersion.text = "当前版本:" + GameConfig.Version;

            StartCoroutine(InitGame());
        }
    }

    /// <summary>
    /// 获取并校对服务器与本地清单资源包，将需下载资源包加入下载队列
    /// </summary>
    /// <returns></returns>
    private IEnumerator CheckResources()
    {
        string s = "检查更新";
        txtRes.text = s;

        WWW www = new WWW(GameConfig.AssetIP + "/assetslist.txt");
        int index = 0;
        while (www.isDone == false)
        {
            txtRes.text = s + "...".Substring(index);
            index = (index + 1) % 2;
            yield return new WaitForEndOfFrame();
        }

        if (string.IsNullOrEmpty(www.error) == false) //获取错误，等待5秒继续检测
        {
            Debug.Log(www.url + "\n" + www.error);
            yield return new WaitForSeconds(5f);
            StartCoroutine(CheckResources());
        }
        else
        {
            string[] arr = www.text.Split('\n');
            timeServerString = arr[0];
            dicServer = CreateAssetDictionary(arr);

            if (File.Exists(GameConfig.assetBundlePath + "/assetslist.txt") == true)
            {
                arr = File.ReadAllText(GameConfig.assetBundlePath + "/assetslist.txt").Split('\n');

                timeLocalString = arr[0];
                dicLocal = CreateAssetDictionary(arr);
                txtVersion.text = "当前版本:" + GameConfig.Version;
            }
            else
            {
                timeLocalString = "0";
                dicLocal = new Dictionary<string, AssetBundleInfo>();
            }
            yield return new WaitForEndOfFrame();
            if (timeServer > timeLocal)
            {
                foreach (var item in dicServer.Values)
                {
                    if (dicLocal.ContainsKey(item.name) == false)
                    {
                        allSize += item.size;
                        listDown.Add(item);
                    }
                    else if (dicLocal[item.name].md5 != item.md5)
                    {
                        allSize += item.size;
                        listDown.Add(item);
                    }
                }

                StartCoroutine(DownAssets());
            }
            else
            {
                StartCoroutine(InitGame());
            }
        }
    }

    /// <summary>
    /// 根据下载队列开始下载资源到本地目录（Window为：根目录/PersistentData）
    /// </summary>
    /// <returns></returns>
    private IEnumerator DownAssets()
    {
        txtRes.text = "正在下载更新文件";
        txtSize2.text = "0%";
        txtSize.text = string.Format("{0}MB/{1}", (downSize).ToString("0.00"), GetSize(allSize));
        txtSpeed.text = "0KB/S";
        progressBar.value = 0;
        progressBar.gameObject.SetActive(true);
        for (int i = 0; i < listDown.Count; i++)
        {
            AssetBundleInfo ab = listDown[i];
            WWW www = new WWW(GameConfig.AssetIP + "/" + ab.name + "_" + ab.md5);
            while (www.isDone == false)
            {
                yield return new WaitForEndOfFrame();
                progressBar.value = (1f * (downSize + www.bytesDownloaded)) / allSize;
                txtSize.text = string.Format("{0}/{1}", GetSize(downSize + www.bytesDownloaded), GetSize(allSize));
                txtSpeed.text = string.Format("{0}/S", GetSize(www.bytesDownloaded / Time.deltaTime));
                txtSize2.text = (progressBar.value * 100).ToString("0.00") + "%";
            }

            if (string.IsNullOrEmpty(www.error) == false)
            {
                Debug.Log(ab.name + " " + www.error + " " + www.url);
                yield return new WaitForSeconds(5f);
                i--;
                continue;
            }
            downSize += www.bytesDownloaded;
            File.WriteAllBytes(GameConfig.assetBundlePath + "/" + ab.name, www.bytes);

            dicLocal[ab.name] = ab;
            if (i == listDown.Count - 1)
            {
                timeLocalString = timeServerString;
            }
            SaveLocal();
        }
        StartCoroutine(InitGame());
    }

    private void SaveLocal()
    {
        string txt = timeLocalString;

        foreach (var item in dicLocal.Values)
        {
            txt += "\n" + item.type + "," + item.name + "," + item.md5 + "," + item.size;
        }

        File.WriteAllText(GameConfig.assetBundlePath + "/assetslist.txt", txt);
    }

    private string GetSize(float v)
    {
        if (v < 1024)
            return v + "K";
        if (v < 1024 * 1024)
            return (v / 1024f).ToString("0.00") + "KB";
        if (v < 1024 * 1024 * 1024)
            return (v / (1024f * 1024f)).ToString("0.00") + "MB";
        return "";
    }

    /// <summary>
    /// 根据list获取ab包信息（非下载）
    /// </summary>
    /// <param name="arrServerList"></param>
    /// <returns></returns>
    private Dictionary<string, AssetBundleInfo> CreateAssetDictionary(string[] arrServerList)
    {
        Dictionary<string, AssetBundleInfo> result = new Dictionary<string, AssetBundleInfo>();
        for (int i = 1; i < arrServerList.Length; i++)
        {
            if (string.IsNullOrEmpty(arrServerList[i]) == true)
                continue;
            string[] arr = arrServerList[i].Split(',');
            AssetBundleInfo ab = new AssetBundleInfo(int.Parse(arr[0]), arr[1], arr[2], float.Parse(arr[3]));
            result.Add(ab.name, ab);
        }
        return result;
    }

    /// <summary>
    /// 游戏初始化，开启各个基础组件，同时预先加载lua等重要资源
    /// </summary>
    /// <returns></returns>
    private IEnumerator InitGame()
    {
        progressBar.gameObject.SetActive(true);
        progressBar.value = 0f;
        yield return new WaitForEndOfFrame();

        LoadTools.Init();

        this.gameObject.SetActive(false);
        Debug.Log("【UIGameLoading——InitGame】:over load");
#if UNITY_STANDALONE_WIN
        luaABname = "";
        if (luaABname == "")
        {
            foreach (string key in dicLocal.Keys)
            {

                if (key.IndexOf("lua") != -1)
                {
                    luaABname = key;
                    Debug.Log("luaABname == " + luaABname);
                    ResourceManager.luaFileName = luaABname;
                }
            }
        }
        ResourceManager.loadLuaToByte(luaABname);
#endif

        GameObject go = Resources.Load<GameObject>("Main");
        Instantiate(go);
    }
}

public class AssetBundleInfo
{
    public string name;
    public string md5;
    public float size;
    public int type;

    public AssetBundleInfo(int type, string name, string md5, float size)
    {
        this.type = type;
        this.name = name;
        this.size = size;
        this.md5 = md5;
    }
}